package org.zoomdy.gdbserver.extender;

import java.io.*;
import java.net.*;

public class Head extends End
{
    public Head()
    {
        _listenPort = 9000;
    }
    
    public boolean start()
    {
        _startNoAckMode = false;
        
        if(!super.start())
        {
            return false;
        }
        
        try
        {
            this._serverSocket = new ServerSocket(_listenPort);
        }
        catch(IOException e)
        {
            System.err.printf("创建监听服务器失败，监听端口：%d，可能已经被占用！\n", _listenPort);
            return false;
        }
        
        HeadThread target = new HeadThread();
        this._headThread = new Thread(target);
        this._headThread.start();
        
        return true;
    }
    
    public void stop()
    {
        try
        {
            // 关闭服务器Socket，服务线程检测到服务器Socket被关闭后，退出服务线程
            this._serverSocket.close();
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }
    }
    
    public boolean setProperty(String name, String value)
    {
        if(name.equals("listenPort"))
        {
            int port = Integer.parseInt(value);
            if(port > 0)
            {
                this._listenPort = port;
                return true;
            }
        }
        
        return false;
    }
    
    public String getProperty(String name)
    {
        if(name == "listenPort")
        {
            return Integer.toString(this._listenPort);
        }
        
        return null;
    }
    
    protected Packet getPacket()
    {
        Packet pkt = super.getPacket();
        if((pkt != null) && pkt.startsWith("QStartNoAckMode"))
        {
            _startNoAckMode = true;
        }
        
        return pkt;
    }
    
    protected boolean putPacket(Packet pkt)
    {
        if(_startNoAckMode)
        {
            if(pkt.toString().equals("OK"))
            {
                this.setAckMode(false);
            }
            else
            {
                this.setAckMode(true);
            }
            _startNoAckMode = false;
        }
        return super.putPacket(pkt);
    }
    
    public boolean inputCommand(Packet pkt)
    {
        // 不能向头节点输入命令，头节点是命令的源头
        return false;
    }
    
    public boolean inputResponse(Packet pkt)
    {
        return putPacket(pkt);
    }
    
    private boolean acceptClient()
    {
        try
        {
            System.out.println("============================================================");
            System.out.printf("服务已开启，监听端口：%d，等待连接。\n", _listenPort);
            this._clientSocket = this._serverSocket.accept();
            this._inStream = this._clientSocket.getInputStream();
            this._outStream = this._clientSocket.getOutputStream();
            SocketAddress addr = this._clientSocket.getRemoteSocketAddress();
            System.out.printf("已与 %s 建立连接。\n", addr.toString());
            
            return this.connect();
        }
        catch(IOException e)
        {
            System.err.printf("因异常而终止服务！\n");
            return false;
        }
    }
    
    private void closeClient()
    {
        try
        {
            if(this._clientSocket != null)
            {
                this._clientSocket.close();
                SocketAddress addr = this._clientSocket.getRemoteSocketAddress();
                System.out.printf("已与 %s 断开连接。\n", addr.toString());
            }
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }
    }
    
    private class HeadThread implements Runnable
    {
        public void run()
        {
            // 监听服务循环
            while(!Head.this._serverSocket.isClosed())
            {
                if(!Head.this.acceptClient())
                {
                    break;
                }
                
                // 连接服务循环
                while(!Head.this._clientSocket.isClosed())
                {
                    Packet pkt = Head.this.getPacket();
                    if(pkt == null)
                    {
                        Head.this.closeClient();
                        break;
                    }
                    
                    boolean ret = Head.this.outputCommand(pkt);
                    if(!ret)
                    {
                        Head.this.closeClient();
                        break;
                    }
                }
                
                // 断开连接时，向GDBServer发送Ctrl+C
                Packet pkt = Packet.makeCtrlCPacket();
                Head.this.outputCommand(pkt);
            }
        }
    }
    
    private ServerSocket _serverSocket;
    private int _listenPort;
    private Thread _headThread;
    private boolean _startNoAckMode;
}
